

package jetbrains.buildServer.server.rest.model.buildType;

import jetbrains.buildServer.ServiceLocator;
import jetbrains.buildServer.buildTriggers.BuildTriggerDescriptor;
import jetbrains.buildServer.server.rest.data.PermissionChecker;
import jetbrains.buildServer.server.rest.errors.BadRequestException;
import jetbrains.buildServer.server.rest.model.Fields;
import jetbrains.buildServer.server.rest.swagger.annotations.ModelBaseType;
import jetbrains.buildServer.server.rest.swagger.constants.ObjectType;
import jetbrains.buildServer.server.rest.util.BeanContext;
import jetbrains.buildServer.server.rest.util.BuildTypeOrTemplate;
import jetbrains.buildServer.server.rest.util.ValueWithDefault;
import jetbrains.buildServer.serverSide.BuildTypeSettings;
import jetbrains.buildServer.serverSide.BuildTypeSettingsEx;
import jetbrains.buildServer.util.CollectionsUtil;
import jetbrains.buildServer.util.Converter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Yegor.Yarko
 *         Date: 05.01.12
 */
@XmlRootElement(name="triggers")
@ModelBaseType(ObjectType.LIST)
@SuppressWarnings("PublicField")
public class PropEntitiesTrigger {
  @XmlAttribute
  public Integer count;
  @XmlElement(name = "trigger")
  public List<PropEntityTrigger> propEntities;

  public PropEntitiesTrigger() {
  }

  public PropEntitiesTrigger(final BuildTypeSettingsEx buildType, @NotNull final Fields fields, @NotNull final BeanContext beanContext) {
    final Collection<BuildTriggerDescriptor> buildTriggersCollection = buildType.getBuildTriggersCollection();
    propEntities = ValueWithDefault.decideDefault(fields.isIncluded("trigger"), new ValueWithDefault.Value<List<PropEntityTrigger>>() {
      @Nullable
      public List<PropEntityTrigger> get() {
        return CollectionsUtil.convertCollection(buildTriggersCollection, new Converter<PropEntityTrigger, BuildTriggerDescriptor>() {
          public PropEntityTrigger createFrom(@NotNull final BuildTriggerDescriptor source) {
            return new PropEntityTrigger(source, buildType, fields.getNestedField("trigger", Fields.NONE, Fields.LONG), beanContext);
          }
        });
      }
    });
    count = ValueWithDefault.decideIncludeByDefault(fields.isIncluded("count"), buildTriggersCollection.size());
  }

  public boolean setToBuildType(final BuildTypeOrTemplate buildType, final ServiceLocator serviceLocator) {
    serviceLocator.getSingletonService(PermissionChecker.class).checkCanEditBuildTypeOrTemplate(buildType);
    BuildTypeSettingsEx settings = buildType.getSettingsEx();

    Storage original = new Storage(settings);
    try {
      removeAllTriggers(settings);
      if (propEntities != null) {
        for (PropEntityTrigger entity : propEntities) {
          entity.addToInternalUnsafe(settings, serviceLocator);
        }
      }
      return true;
    } catch (Exception e) {
      //restore original settings
      original.apply(settings);
      throw new BadRequestException("Error setting triggers", e);
    }
  }

  public static void removeAllTriggers(final BuildTypeSettings buildType) {
    for (BuildTriggerDescriptor entry : buildType.getBuildTriggersCollection()) {
      buildType.removeBuildTrigger(entry);
    }
  }

  public static class Storage {
    public final Map<BuildTriggerDescriptor, Boolean> deps = new LinkedHashMap<>();

    public Storage(final @NotNull BuildTypeSettings buildTypeSettings) {
      for (BuildTriggerDescriptor entity : buildTypeSettings.getBuildTriggersCollection()) {
        deps.put(entity, buildTypeSettings.isEnabled(entity.getId()));
      }
    }

    public void apply(final @NotNull BuildTypeSettings buildTypeSettings) {
      removeAllTriggers(buildTypeSettings);
      for (Map.Entry<BuildTriggerDescriptor, Boolean> entry : deps.entrySet()) {
        buildTypeSettings.addBuildTrigger(entry.getKey());
        buildTypeSettings.setEnabled(entry.getKey().getId(), entry.getValue());
      }
    }
  }
}